# -*- coding: utf-8 -*-
import datetime
import random
import numpy as np
from view.loadSaveDB import loadSaveDB


class RandomSampleBlocks:

    def __init__(self, data, label):
        self.data = data
        self.rows = data.shape[0]
        self.label = label
        self.cluster = len(np.unique(label))
        self.randomSampleBlocks = None
        self.randomSampleBlocks_labels = None

    def partition(self, hdfs_block_num, rsp_block_num):
        tmpidxs = list(range(self.rows))
        # idxs = []
        # for size in sizeLst:
        #     idxs.append(tmpidxs[:size])
        idxs = self.rsp(hdfs_block_num, rsp_block_num, np.asarray(tmpidxs))

        self.randomSampleBlocks = []
        self.randomSampleBlocks_labels = []
        for blockidxs in idxs:
            blockidxs = blockidxs.astype(int)
            self.randomSampleBlocks.append(self.data[blockidxs, :])
            self.randomSampleBlocks_labels.append(self.label[blockidxs])
        self._fixLabels()

    def _fixLabels(self):
        fixedLabels = []
        for label in self.randomSampleBlocks_labels:
            fixedLabels.append(label)
            label_block = np.unique(label)
            nclusters_block = len(label_block)
            if list(label_block) == list(range(nclusters_block)):
                continue
            for i, t in enumerate(label_block):
                idxs = np.where(label == t)[0]
                label[idxs] = i
            fixedLabels[-1] = label
        self.randomSampleBlocks_labels = fixedLabels

    def saveToDB(self, des, fileName, name, limit=None):
        lsd = loadSaveDB()
        ids = []
        for data, label in zip(self.randomSampleBlocks, self.randomSampleBlocks_labels):
            data = np.concatenate((label[:, np.newaxis], data), axis=1)
            id = lsd.saveDBForDataset(data=data, des=des, fileName=fileName, nClusters=max(label)+1, name=name,
                                      haveLabels=True, confirm=True)
            ids.append(id)
            if limit is not None and len(ids) == limit:
                return ids
        return ids

    def rsp(self, hdfs_block_num, rsp_block_num, data):
        np.random.seed(1)
        print("{0}\tGenerating RSP ...".format(datetime.datetime.now()))
        # LOAD DATA
        D = data
        if D.ndim == 1:
            D = D[:, np.newaxis]

        total_size = D.shape[0]
        print(D.shape)

        # Divide D into hdfs_block_num non-overlapping subsets {Di} of equal size. These subsets form a partition of D
        end = total_size-(total_size % (hdfs_block_num*rsp_block_num))
        block_size = int(end / hdfs_block_num)
        block_idx = [i for i in range(0, end, block_size)]  # hdfs block, 通过索引的方式，从而避免使用三维结构
        print(total_size)
        print(total_size - end)

        # Randomize each Di for 1 ≤ i ≤ hdfs_block_num;
        for i in range(hdfs_block_num):
            randidx = np.random.permutation(range(block_idx[i], block_idx[i]+block_size))
            D[block_idx[i]:block_idx[i]+block_size, :] = D[randidx, :]
        if end != total_size:
            randidx = np.random.permutation(range(end, total_size))
            D[end:, :] = D[randidx, :]

        # Cut each randomized Di into rsp_block_num slices {D(i, j)}
        slice_size = int(block_size / rsp_block_num)
        slice_idx = np.array([[i for i in range(j, j+block_size, slice_size)] for j in block_idx])

        # merge the slices of {D(i, j)}  for 1 ≤ i ≤ hdfs_block_num to form the rsp_block subsets j
        rsp_size = hdfs_block_num * slice_size
        rsp_data = np.zeros((0, D.shape[1]))
        rsp_idx = []
        if end != total_size:
            offcut_size = slice_size * (total_size - end) / block_size
            offcut_idx = [i for i in range(end, total_size, offcut_size)]
            rsp_size = rsp_size + offcut_size
        for i in range(rsp_block_num):  # 第i块rsp块
            for j in range(hdfs_block_num):  # hdfs块
                rsp_data = np.concatenate((rsp_data, D[slice_idx[j, i]:slice_idx[j, i]+slice_size, :]))
            # filling-in
            if end != total_size:
                rsp_data = np.concatenate((rsp_data, D[offcut_idx[i]:offcut_idx[i] + offcut_size, :]))
            rsp_idx.append(i*rsp_size)

        # SAVE DATA
        rsp_data_lst = []
        for i in rsp_idx:
            rsp_data_lst.append(rsp_data[i:i+rsp_size].flatten())
        return rsp_data_lst
